package com.musicdaze.utils.math;

/**
 * Represents a Vector with 2 elementss
 * @author mfujihara
 * 
 */
public class Vector2 {
  /** the x of this vector **/
  public float x;
  /** the y of this vector **/
  public float y;
  
	public int id;// used for debugging purposes

  /**
   * public construct sets x=y=0
   */
  public Vector2() {
    this.x = 0;
    this.y = 0;
  }

  /**
   * public constructor with initialization for x and y
   * @param x the value to set x as
   * @param y the value to set y as
   */
  public Vector2(float x, float y) {
    this.x = x;
    this.y = y;
  }

  /**
   * creates a vector from input vector
   * @param position the vector to copy
   */
  public Vector2(Vector2 position) {
    this.x = position.x;
    this.y = position.y;
  }
  /**
   * subtracts v from this vector. mutate
   * @param v the vector to subtract from this
   * @return this
   */
  public Vector2 sub(Vector2 v){
    this.x -= v.x;
    this.y -= v.y;
   return this;
  }
  /**
   * adds v to this vector. mutate
   * @param v the vector to add to this
   * @return this
   */
  public Vector2 add(Vector2 v) {
    this.x += v.x;
    this.y += v.y;
    return this;
  }

  /**
   * sets this vector with values from as. mutate
   * @param as the vector to set to
   */
  public void set(Vector2 as) {
    this.x = as.x;
    this.y = as.y;
  }

  /**
   * scales this vector. mutate
   * @param s the value to scale this vector by
   * @return this
   */
  public Vector2 scale(float s) {
    this.x *= s;
    this.y *= s;
    return this;
  }

  /**
   * Returns the magnitude of this vector
   * @return the magnitude of this vector
   */
  public float mag() {
    return (float) Math.sqrt(x * x + y * y);
  }

  /**
   * Normalizes this vector.
   * @return this
   */
  public Vector2 normalize() {
    this.scale(1 / mag());
    return this;
  }
  /**
   * the dot product
   * @param v the vector to dot with
   * @return the dot product
   */
  public float dot(Vector2 v){
    return v.x*x + v.y*y;
  }
  /**
   * gets the distance from this vector to point assuming both are points in 2d
   * space
   * @param point the point to find the distance to
   * @return the distance between this and point
   */
  public float distanceTo(Vector2 point) {
    Vector2 diff = Vector2.sub(this, point);
    return diff.mag();
  }

  /**
   * checks values of x and y for equality
   * @param o the object o check equality with
   * @return true if objects are equal based on x and y; false otherwise
   */
  public boolean equals(Object o) {
    if (o instanceof Vector2) {
      Vector2 v = (Vector2) o;
      return v.x == this.x && v.y == this.y;
    }
    return false;
  }

  /**
   * uses (int)(x+y)
   * @return hashcode
   */
  public int hashCode() {
    return (int) (x + y);
  }

  /**
   * prints out (x,y)
   * @return (x,y)
   */
  @Override
  public String toString() {
    return "(" + this.x + "," + this.y + ")";
  }
  
  /** 
   * Returns a new instance of the vector point with same x and y
   * @return cloned vector point
   */
  public Vector2 clone() {
  	Vector2 newVector = new Vector2(this.x, this.y);
  	newVector.id = this.id;
  	return newVector;
  }

  /**
   * adds 2 vectors together without mutating them
   * @param a vector to add
   * @param b vector to add
   * @return a vector that is the sum of a and b
   */
  public static Vector2 add(Vector2 a, Vector2 b) {
    Vector2 ret = new Vector2(a.x + b.x, a.y + b.y);
    return ret;
  }

  /**
   * subtracts 2 vectors together without mutating them
   * @param a vector to subtract from
   * @param b vector to subtract
   * @return Vector2 that is a - b
   */
  public static Vector2 sub(Vector2 a, Vector2 b) {
    Vector2 ret = new Vector2(a.x - b.x, a.y - b.y);
    return ret;
  }
  /**
   * Gets the angle between a to b
   * @param a the start vector
   * @param b the end vector
   * @return the angle between two vectors
   */
  public static float angleBetween(Vector2 a, Vector2 b){
    float dot = a.dot(b);
    dot = dot/a.mag();
    dot = dot/b.mag();
    return (float) Math.acos(dot);
  }
  /**
   * Gets the bearing in polar coordinates theta
   * @param from the start of the vector
   * @param to the end of the vector
   * @return the bearing in polar coordinates theta
   */
  public static float getBearing(Vector2 from, Vector2 to){
    Vector2 diff = to.sub(from);
    return (float) Math.atan2(diff.y, diff.x);
  }
}
